#!/usr/bin/env python

'''Mini library for RPM.

Pure Python library for RPM Package Manager.
'''

import sys
from struct import unpack

Magic = '\xed\xab\xee\xdb'
Type = ('Binary', 'Source')
Architecture = (
    None, 'i386', 'Alpha', 'Sparc', 'MIPS', 'PowerPC', '68000',
    'SGI', 'RS6000', 'IA64', 'Sparc64', 'MIPSel', 'ARM',
    '68000int', 's390/i370', 's390x', 'PowerPC64', 'SuperH', 'Xtensa', )
OS = (
    None, 'Linux', 'IRIX', 'SunOS5', 'SunOS4', 'AmigaOS/AIX', 'HP-UX',
    'OSF1', 'FreeBSD', 'SCO_SV', 'IRIX64', 'NEXTPSTEP', 'BSD_OS',
    'machten', 'CYGWIN32_NT', 'CYGWIN32_95', 'UNIX_SV', 'MiNT', 'OS/390',
    'VM/ESA', 'Linux/390', 'Darwin', )

class RPMError(Exception):
    pass

class RPM(object):
    def __init__(self, rpmpath=None):
        self.name = ''
        self.handler = None
        self.valid = False
        if rpmpath:
            if type(rpmpath) == str:
                self.open(rpmpath)
            if type(rpmpath) == file:
                self.handler = rpmpath

    def __str__(self):
        return "%s RPM %s for %s %s" % (
            Type[self.metadata['type']],
            self.metadata['name'],
            OS[self.metadata['os']],
            Architecture[self.metadata['architecture']])
    
    def open(self, pathname):
        self.handler = open(pathname)

    def read(self):
        self._lead = self.handler.read(96)
        self.data = self.handler.read()
        if self._lead[0:4] != Magic:
            raise RPMError, "not a RPM"
        else:
            self.valid = True
        major, minor, type_, archnum = unpack('>BBHH', self._lead[4:10])
        name = self._lead[10:76]
        osnum, signature_type = unpack('>HH', self._lead[76:80])
        self.metadata = {
            'name': name,
            'version': '%s.%s' % (major, minor),
            'type': type_,
            'architecture': archnum,
            'os': osnum,
            'signature': signature_type,
        }

    def save(self, filepath):
        pass

    def to_compressed_cpio(self, stream=sys.stdout):
        idx = self.data.find('\x1f\x8b') # Find gzip MAGIC
        if idx == -1:
            raise RPMError, "Could not find compressed cpio"
        gzdata = self.data[idx:]
        stream.write(gzdata)

    def close(self):
        self.handler.close()
        self.handler = None
        self.valid = False

def main(argv=None):
    if argv == None:
        argv = sys.argv[1:]
    if argv == []:
        return 0
    command = argv[0]
    args = argv[1:]
    if command in ('help'):
        print 'Usage:', sys.argv[0], '[help] [info args] [cpiogz]'
        return 0
    elif command in ('info'):
        for arg in args:
            try:
                r = RPM(arg)
                r.read()
            except RPMError, e:
                print 'Error:', arg, e
                continue
            else:
                print r
                r.close()
    elif command in ('cpiogz', 'gpgz'):
        for arg in args:
            r = RPM(arg)
            r.read()
            r.to_compressed_cpio()
            r.close()
    else:
        print 'Error: unknown command', command
        return 1

if __name__ == '__main__':
    sys.exit(main())
